/*
 * Copyright 2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.seppiko.chart.utils;

import com.google.zxing.qrcode.encoder.ByteMatrix;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Rectangle;
import java.io.Writer;
import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGeneratorContext;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.svggen.SVGGraphics2DIOException;
import org.seppiko.chart.utils.logging.LoggingManager;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
//import org.w3c.dom.Element;

/**
 * @author Leonard Woo
 */

public class SVGUtil {

  private static final LoggingManager Logger = LoggingManager.getInstance().getLogger(SVGUtil.class.getName());

  private static SVGGraphics2D initSVGGraphics2D() {
    DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
    // Create an instance of org.w3c.dom.Document.
    Document document = domImpl.createDocument("http://www.w3.org/2000/svg", "svg", null);
    // Create an instance of the SVG Generator.
    SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
    ctx.setComment("Generated by Batik SVG Generator");
    return new SVGGraphics2D(ctx, false);
  }

  public static void toSVGDocument(ByteMatrix matrix, String content, Writer out, int width, int height, int margin, int color, int backgroundColor) {

    Color fg = new Color(color);
    Color bg = new Color(backgroundColor);

    int inputWidth = matrix.getWidth();
    int inputHeight = matrix.getHeight();

    int matrixWidth = inputWidth + (margin * 2);
    int matrixHeight = inputHeight + (margin * 2);

    int outputWidth = Math.max(width, matrixWidth);
    int outputHeight = Math.max(height, matrixHeight);

    int multiple = Math.min(outputWidth / matrixWidth, outputHeight / matrixHeight);
//    int cellWidth = outputWidth / matrixWidth;
//    int cellHeight = outputHeight / matrixHeight;

    int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
    int topPadding = (outputHeight - (inputHeight * multiple)) / 2;

//    int fontsize = 12 * (width / 128);
//    if(fontsize <= 0 ) {
//      fontsize = 12;
//    }

    Font font = new Font("Arial", Font.PLAIN, 18);
    int fontSize = content != null ? font.getSize() : 0;
//    int cellHeight = outputHeight - margin * 2 - fontSize;

    SVGGraphics2D g2d = initSVGGraphics2D();

//    Element root = g2d.getRoot();
//    root.setAttributeNS(null, "viewBox", "0 0 " + outputWidth + " " + (outputHeight + fontSize) );
    g2d.setSVGCanvasSize(new Dimension(outputWidth, outputHeight + fontSize));
//    root.setAttributeNS(null, "width", "" + outputWidth);
//    root.setAttributeNS(null, "height", "" + (outputHeight + fontSize) );

    g2d.setColor(bg);
    g2d.fill(new Rectangle(0, 0, outputWidth, outputHeight + fontSize));

    g2d.setColor(fg);
//    g2d.setStroke(new BasicStroke(1.0f));
    for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
      for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
        if (matrix.get(inputX, inputY) == 1) {
//          if (g2d.getColor() != fg) {
//            g2d.setColor(fg);
//          }
          g2d.fill(new Rectangle(outputX, outputY, multiple, multiple));
//        } else {
//          if (g2d.getColor() != bg) {
//            g2d.setColor(bg);
//          }
//          g2d.fill(new Rectangle(outputX, outputY, multiple, multiple));
        }
      }
    }

    if (content != null) {
      FontMetrics fm = g2d.getFontMetrics(font);
      int textWidth = fm.stringWidth(content);
      float fontX = (float) (outputWidth / 2 - textWidth / 2);
      Logger.info("X >>> " + textWidth + " >>>" + fontX);
      float fontY = margin + outputHeight + ((font.getSize() + 0.0f) / 2);
      Logger.info("Y >>> " + font.getSize() + " >>>" + fontY);
      g2d.setFont(font);
      g2d.drawString(content, fontX, fontY);
    }

    try {
//      g2d.stream(root, out, false, false);
      g2d.stream(out, false);
    } catch (SVGGraphics2DIOException ex) {
      Logger.error("SVG create is fail.", ex);
    } finally {
      g2d.dispose();
    }
  }

  public static void toSVGDocument(boolean[] code, Writer out, String content, int width, int height, int margin, int color, int backgroundColor) {

    Color fg = new Color(color);
    Color bg = new Color(backgroundColor);

    int fontsize = 12 * (width / 128);
    if(fontsize <= 0 ) {
      fontsize = 12;
    }

    Font font = new Font("Arial", Font.PLAIN, fontsize);

    int inputWidth = code.length;

//    int matrixWidth = inputWidth + (margin * 2);
//    int matrixHeight = height + (margin * 2);

//    int outputWidth = Math.max(width, matrixWidth);
//    int outputHeight = Math.max(height, matrixHeight);

    int cellWidth = Math.round( ((float) (width - margin * 2)) / (float) inputWidth );

//    int cellHeight = outputHeight / matrixHeight;
    int cellHeight = height - margin * 2 - (content != null ? font.getSize() : 0);

    int outputWidth = Math.max(width, cellWidth * inputWidth + margin * 2);

//    int leftPadding = (outputWidth - (inputWidth * cellWidth)) / 2;
//    int topPadding = (outputHeight - (height * cellHeight)) / 2;
    int leftPadding = margin;

    SVGGraphics2D g2d = initSVGGraphics2D();

//    Element root = g2d.getRoot();
//    root.setAttributeNS(null, "viewBox", "0 0 " + outputWidth + " " + height );
    g2d.setSVGCanvasSize(new Dimension(outputWidth, height));
//    root.setAttributeNS(null, "width", "" + outputWidth);
//    root.setAttributeNS(null, "height", "" + height );

    g2d.setColor(bg);
    g2d.fill(new Rectangle(0, 0, outputWidth, height));

    g2d.setColor(fg);

    int codeHeight = margin;

    g2d.setStroke(new BasicStroke());
    for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += cellWidth) {
      if (code[inputX]) {
//        if (g2d.getColor() != fg) {
//          g2d.setColor(fg);
//        }
        g2d.fill(new Rectangle(outputX, codeHeight, cellWidth, cellHeight));
//      } else {
//        if (g2d.getColor() != bg) {
//          g2d.setColor(bg);
//        }
//        g2d.fill(new Rectangle(outputX, codeHeight, cellWidth, cellHeight));
      }
    }

    if (content != null) {
      FontMetrics fm = g2d.getFontMetrics(font);
      int textWidth = fm.stringWidth(content);
      float fontX = (float) (outputWidth / 2 - textWidth / 2);
      Logger.info(">>> " + textWidth + " >>>" + fontX);
      float fontY = margin + cellHeight + font.getSize();
      g2d.setFont(font);
      g2d.drawString(content, fontX, fontY);
    }

    try {
//      g2d.stream(root, out, false, false);
      g2d.stream(out, false);
    } catch (SVGGraphics2DIOException ex) {
      Logger.error("SVG create is fail.", ex);
    } finally{
      g2d.dispose();
    }
  }

}
